#pragma once
// #include "General.h"
#include <vulkan/vulkan_raii.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <algorithm>
#include <vector>
#include <ranges>
#include <iostream>
#include <filesystem>

#include <set>
#include <map>

#include "Scene/Mesh.hpp"
#include "Core/Context/LumineContext.hpp"
#include "Core/Pipeline/LuminePipeline.hpp"
#include "Utils/LumineUtils.hpp"
#include "Core/Swapchain/LumineSwapchain.hpp"
#include "Core/Renderer/LumineRenderer.hpp"
namespace Lumine
{
    constexpr uint32_t WIDTH = 800;
    constexpr uint32_t HEIGHT = 600;
    class VulkanBase
    {
    private:
        bool framebufferResized = false;
        GLFWwindow *m_window;
        GLFWmonitor *m_monitor;

        LumineSwapchain m_swapchain;
        LumineRenderer m_renderer;
        LuminePipeline m_pipeline;

        void createWindow();

        void initVulkan();

        void cleanup();

        void createVertex();

        void createIndex();

        void createTexture();

        void createDepthResources();

        void createUniform();

public:

        static vk::Format findSupportedFormat(const std::vector<vk::Format> &candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features)
        {
            for (const auto format : candidates)
            {
                vk::FormatProperties props = LumineContext::Get().PhysicalDevice().getFormatProperties(format);
                if (tiling == vk::ImageTiling::eLinear && (props.linearTilingFeatures & features) == features)
                {
                    return format;
                }
                if (tiling == vk::ImageTiling::eOptimal && (props.optimalTilingFeatures & features) == features)
                {
                    return format;
                }
            }
            throw std::runtime_error("failed to find supported format!");
        }

        static vk::Format findDepthFormat()
        {
            std::vector<vk::Format> formats = {vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint};
            return findSupportedFormat(formats, vk::ImageTiling::eOptimal, vk::FormatFeatureFlagBits::eDepthStencilAttachment);
        }

        bool hasStencilComponent(vk::Format format)
        {
            return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
        }

    public:
        VulkanBase();

        ~VulkanBase();

        void run()
        {
            mainLoop();
        }

        void mainLoop();

        static void framebufferResizeCallback(GLFWwindow * window,int width,int height);
    };
}
